FreeRTOS integration (Alpha)

Warning This is an advanced topic. The rtos integration is only needed under very specific circumstances.
Note We highly recommend to stay away from this integration if you do not have the specific use case. The eTrice execution environment already supports cooperative "multithreading" with message passing out of the box without the need for a RTOS.

Motivation

If you are integrating already existing c or c++ libraries with the miniHIL you sometimes cannot influence the execution model used by the library. If your library needs its own thread context e.g. to be able to "busy" wait for external events the freeRTOS integration might be a solution.

The current integration state is not meant to give you a full featured rtos environment. Currently there are quite a few limitations which have to be considered when using it.

Limitations

  • The generated eTrice environment is still single threaded

    • It is executed in its own thread and never yields.

    • The eTrice thread has the priority 2.

  • All user threads must have a priority > 2.

    • The user threads will block the eTrice thread as long as they do not yield

    • → The user code can block the miniHIL system the same way you can block it by executing long running code in an interrupt context.

    • → To ensure system responsiveness, it is the users responsibility to yield (e.g. by waiting for a semaphore) to the eTrice thread in a timely manner.

Known issues

  • Currently the STM32 HAL SysTick is incremented by the SysTick ISR. With the freeRTOS integration the SysTick interrupt priority is very low. Therefore calling STM32 HAL functions which contain HAL_delay(…​) from an interrupt context will freeze the system. This is not an issue if the HAL functions are called from a thread context.

Enabling the integration

  • To build the miniHIL Project with the freeRTOS enabled, set this flavor in the build.gradle file in the YourProjectName/MiniHILProject directory ext.minihilFlavor = "freeRtos"

Examples

You can find an example actor which uses a freeRTOS thread in the SimModelLib in model/minihil/selftest/RtosTask.room:

SimModelLib/minihil/selftest/RtosTask.room
RoomModel minihil.selftest.RtosTask {

	import etrice.api.types.*
	import etrice.api.timer.PTimer
	import etrice.api.logger.PLogger

	ExternalType SemaphoreHandle_t -> "SemaphoreHandle_t" default "NULL"

	ActorClass AActorWithRtosTask {
		Interface {
		}
		Structure {
			usercode1 '''
				#include "FreeRTOS.h"
				#include "task.h"
				#include "semphr.h"
			'''

			SAP timer: PTimer
			SAP logger: PLogger

			Attribute taskSemaphore: SemaphoreHandle_t
			Attribute counter: uint16 = "0"
		}
		Behavior {
			Operation theRtosTask() '''
				while(1) {
					// wait indefinitly for semaphore
					xSemaphoreTake(taskSemaphore, portMAX_DELAY);
					counter++;
				}
			'''
			StateMachine {
				State wait {
					entry '''timer.startTimeout(100);'''
				}
				State active
				Transition init0: initial -> wait
				Transition tr0: wait -> active {
					triggers {
						<timeout: timer>
					}
					action '''
						// create semaphore for task signaling
						taskSemaphore = xSemaphoreCreateBinary();
						xSemaphoreGive(taskSemaphore);
						// start task. As its prio is higher than the etrice tasks prio it will run immediately
						BaseType_t xReturn;
						xReturn = xTaskCreate((void (*)(void *))AActorWithRtosTask_theRtosTask, "actorTask", configMINIMAL_STACK_SIZE, self, 4 | portPRIVILEGE_BIT, NULL);
						// the following lines will be called once the task yields/changes to unready state (e.g. by waiting for a semaphore).
						if (xReturn == pdPASS && NULL != taskSemaphore) {
						    // task successfully created
						}


						timer.startTimer(300);'''
				}
				Transition tr1: active -> active {
					triggers {
						<timeout: timer>
					}
					action '''
						logger.logF("Count: %d", counter);
						xSemaphoreGive(taskSemaphore);
					'''
				}
			}
		}
	}
}